use std::convert::Infallible;

use apikit::rpc::FormParts;
use apikit::rpc::{ParamAppender, RequestParamSign};
use reqwest::multipart::Form;
use reqwest::{RequestBuilder, multipart::Part};

use crate::{
    dto::FileItem,
    param::{__TypeMapper, Multipart},
};

impl<T: FormParts> RequestParamSign<Multipart<T>> for __TypeMapper {
    type Input = Multipart<T>;
}

impl<T: FormParts> ParamAppender<RequestBuilder> for Multipart<T> {
    type Error = Infallible;

    fn append_param(self, builder: RequestBuilder) -> Result<RequestBuilder, Self::Error> {
        let form = Form::new();
        let form = T::form_parts(self.0, form, String::default());
        let builder = builder.multipart(form);
        Ok(builder)
    }
}

impl FormParts for FileItem {
    fn form_parts(self, form: reqwest::multipart::Form, name: String) -> reqwest::multipart::Form {
        let mut part = Part::bytes(self.content.bytes.to_vec());
        if let Some(file_name) = self.file_name {
            part = part.file_name(file_name);
        }
        if let Some(mime) = self.content_type {
            let mime_part = part.mime_str(mime.as_str());
            if let Ok(mime_part) = mime_part {
                return form.part(name, mime_part);
            } else {
                return form;
            }
        }
        form.part(name, part)
    }
}
